package com.example.springmvcdemo.controller;

import com.example.springmvcdemo.entity.UserInfo;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;

@RestController
@RequestMapping("/user")
//@RequestMapping是Spring Web MVC应用程序中最常被用到的注解之一
// 它是用来注册接口的路由映射的.表示服务收到请求时，路径为/r1的请求就会调用r1这个方法的代码
// 路由映射：当用户访问一个URL时，将用户的请求对应到程序中某个类的某个方法的过程就叫路由映射
// 既然 @RequestMapping 已经可以达到我们的目的了,我们为什么还要加 @RestController呢？
// 我们把@RestController去掉,再来访问一次:
//程序报了404, 找不到该页面
//这就是@RestController 起到的作用
//一个项目中, 会有很多类, 每个类可能有很多的方法, Spring程序怎么知道要执行哪个方法呢?
//Spring会对所有的类进行扫描, 如果类加了注解@RestController, Spring才会去看这个类里面的方法
//有没有加 @RequestMapping 这个注解,

//@RequestMapping 即可修饰类，也可以修饰方法 ，当修饰类和方法时，访问的地址是类路径 + 方法路径
//@RequestMapping标识一个类：设置映射请求的请求路径的初始信息
//@RequestMapping标识一个方法：设置映射请求请求路径的具体信息

//注意：@RequestMapping的URL 路径最前面加不加/(斜杠)都可以,Spring程序启动时,会进行判断,如果前面没有加/,Spring会拼接上一个/
//@RequestMapping 的URL路径也可以是多层路径, 最终访问时, 依然是 类路径 + 方法路径


public class UserController {
    @RequestMapping("/r1")
    public String r1(){
        return "hello Spring MVC";
    }

    //@RequestMapping是GET还是POST请求?
    //通过postman可以验证,默认情况下GET和POST请求都可以
    //那如何指定GET或者POST类型呢?
    //注解里，双引号的值会默认赋给"value"这个属性
    // 多个对多个属性赋值，需要写上属性名
    // 只有一个属性时，且属性名为value，可以省略
    //下面就可以执行特定的请求方式为GET请求,POST请求会有下面的错误
    // "status": 405,
    // "error": "Method Not Allowed",
    @RequestMapping(value = "/r2", method = RequestMethod.GET)
    public String r2() {
        return "hello";
    }

    //请求单个参数
    @RequestMapping("/r3")
    public String r3(String name) {
        return "接收到参数 name : " + name;
    }

    //传递多个参数
    //前端如果传递多个参数,那么顺序可以部分先后
    //尽量后端使用包装类来进行接收,如果这里使用int来接收,前端传一个空值,Java中被声明为基本类型而不能转换为空值,所以会报错
    //对于包装类型，如果不传对应参数，Spring接收到的数据则为null
    // 所以企业开发中，对于参数可能为空的数据，建议使用包装类型
    // 如果使用Integer,后端会返回一个null
    @RequestMapping("/r4")
    public String r4(String name, Integer age) {
        return "接收到参数 name : " + name + " age : " + age;
    }

    //传递对象
    //如果参数比较多时，方法声明就需要有很多形参.并且后续每次新增一个参数，也需要修改方法声明.我们不妨把这些参数封装为一个对象
    //SpringMVC也可以自动实现对象参数的赋值
    //Spring会根据参数名称自动绑定到对象的各个属性上，如果某个属性未传递，则赋值为null(基本类型则赋值为默认初识值，比如int类型的属性，会被赋值为0）
    @RequestMapping("/r5")
    public String r5(UserInfo user) {
        return user.toString();
    }

    //后端参数重命名（后端参数映射）
//    某些特殊的情况下，前端传递的参数 key 和我们后端接收的 key 可以不一致，比如前端传递了一个
//    time 给后端，而后端是使用 createtime 字段来接收的，这样就会出现参数接收不到的情况，如果出现
//    这种情况，我们就可以使用 @RequestParam 来重命名前后端的参数值
    // 1.使用 @RequestParam 进行参数重命名时，请求参数只能和 @RequestParam声明的名称一致，才能进行参数绑定和赋值
    // 2.使用@RequestParam 进行参数重命名时,参数就变成了必传参数

    //非必传参数设置如果我们的实际业务前端的参数是一个非必传的参数，针对上述问题，如何解决呢？
    //required 的默认值为true, 表示含义就是: 该注解修饰的参数默认为必传
    //既然如此, 我们可以通过设置 @RequestParam 中的 required=false 来避免不传递时报错，
    //具体实现如下：
    @RequestMapping("/r6")
    public String r6(@RequestParam(value = "age", required = false) Integer UserAge) {
        return "UserAge : " + UserAge;
    }

    //传递数组
    @RequestMapping("/r7")
    public String r7(String[] array) {
        return Arrays.toString(array) + ", length : " + array.length;
    }

    //传递集合
    //集合参数：和数组类似,同一个请求参数名有为多个，且需要使用@RequestParam绑定参数关系默认情况下，请求中参数名相同的多个值，是封装到数组
    // 如果要封装到集合，要使用@RequestParam 绑定参数关系
    @RequestMapping("/r8")
    public String r8(@RequestParam(value = "list", required = false) List<String> list) {
        if (list != null) {
            return list.toString() + ", size : " + list.size();
        }
        return "list为空";
    }

    //传递JSON字符串
    //接收JSON对象, 需要使用 @RequestBody 注解
    //RequestBody: 请求正文，意思是这个注解作用在请求正文的数据绑定，请求参数必须在写在请求正文中
    //如果没有写@RequestBody,那么后端未能成功给UserInfo对象赋值
    @RequestMapping("/r9")
    public String r9(@RequestBody UserInfo userInfo) {
        return userInfo.toString();
    }

    //获取URL中参数
    //@PathVariable
    //和字面表达的意思一样，这个注解主要作用在请求URL路径上的数据绑定默认传递参数写在URL上，SpringMVC就可以获取到
    //如果方法参数名称和需要绑定的URL中的变量名称一致时，可以简写，不用给@PathVariable的属性赋值
    //如上述例子中的id变量如果方法参数名称和需要绑定的URL中的变量名称不一致时，需要@PathVariable的属性value赋值
    @RequestMapping("/r10/{id}/{name}")
    public String r10(@PathVariable(value = "id") Integer id1, @PathVariable String name) {
        return "id : " + id1 + " name : " + name;
    }

    //上传文件
    @RequestMapping("/r11")
    public String r11(@RequestPart MultipartFile file) throws IOException {
        String fileName = file.getOriginalFilename();
        file.transferTo(new File("C:\\Users\\qingdiaoshen\\Desktop\\新建文件夹 (2)\\" + fileName));
        return "获取到上传文件: " + file.getOriginalFilename();
    }
}
